Gas Data
Reading in Data
We first read in two data sets called “gas” representing several
different values having to due with gas stations in the United States.
“Gas” has 72798 observations and 32 total variables.
gas <- read.csv("https://ecoleman451.github.io/website/Data%20Visualization/Datasets/POC.csv")
Mapping
Simple Leaflet
Map
In the following map, each point represents the latitude and
longitude values for a specific gas station (represented by “xcoord” and
“ycoord” respectively in the “gas” data set). Hovering over each point,
you will see the “State”, “County”, “Address”, and “Zip Code” for that
specific gas station. The results are below:
gas_samp <- gas %>% sample_n(500)
# Create a leaflet map
gas_map <- leaflet(data = gas_samp) %>%
addTiles() %>%
addMarkers(
lng = ~xcoord,
lat = ~ycoord,
popup = ~paste("State: ", STATE, "<br>",
"County: ", county, "<br>",
"Address: ", ADDRESS, "<br>",
"Zip Code: ", ZIPnew)
)
# Display the map
gas_map
Leaflet Map
Below, we create a slightly more better leaflet map by using the
“radius” and “color” functions. Here, we have the radius fixed at 5, the
color fixed at blue, and the markers as circle points instead of
location markers. The map is similar to the one above in which each
circle point represents a gas station. Hovering over a point will once
again give the “State”, “County”, “Address”, and “Zip Code” for that
specific gas station.
# Create a leaflet map
gas_map2 <- leaflet(data = gas_samp) %>%
addTiles() %>%
setView(lng = mean(gas_samp$xcoord),
lat = mean(gas_samp$ycoord),
zoom = 13) %>%
addProviderTiles("Esri.WorldGrayCanvas") %>%
addCircleMarkers(
~xcoord,
~ycoord,
color = "blue", # Adjust color as needed
radius = 5, # Adjust radius as needed
stroke = FALSE,
fillOpacity = 0.4,
label = ~paste("State: ", STATE,
"County: ", county,
"Address: ", ADDRESS,
"Zip Code: ", ZIPnew)
) %>%
addLegend(position = "bottomright",
colors = "blue", # Adjust color as needed
labels = "Gas Station",
title = "Gas Stations",
opacity = 0.4)
# Display the map
gas_map2
Best Map
This time, we create a slightly more complex leaflet map by using the
“radius” and “color” functions once again. Here, we have the radius
dependent on the number of POCs (points of compromise) in a gas
station’s respective ZIP Code. This means that the larger a point
appears on the map, the more POCs exist in that station’s ZIP Code. The
color is dependent on whether or not a gas station provides “Fuel”,
“Service Only” or “Both” fuel and services. So, each of those three
categories will have a specific color, representing the services
provided at a specific gas station. In the data, we do not get any gas
stations that provide “Service Only”, so only the categories “Fuel” and
“Both” will appear on the map. The map is similar to the previous maps
above in which each circle point represents a gas station. Hovering over
a point will once again give the “State”, “County”, “Address”, and “Zip
Code” for that specific gas station.
# Create a color palette based on service_or_fuel values
service_palette <- colorFactor(palette = "Set1", domain = gas_samp$service_or_fuel)
# Create the leaflet map
gas_map3 <- leaflet(data = gas_samp) %>%
addTiles() %>%
addProviderTiles("Esri.WorldGrayCanvas") %>%
addCircleMarkers(
~xcoord,
~ycoord,
color = ~service_palette(service_or_fuel), # Use colorFactor
radius = gas_samp$ZIPPOC * 10, # Adjust radius as needed
stroke = FALSE,
fillOpacity = 0.4,
label = ~paste("State: ", STATE, "<br>",
"County: ", county, "<br>",
"Address: ", ADDRESS, "<br>",
"Zip Code: ", ZIPnew)
) %>%
addLegend(position = "bottomright",
colors = service_palette(unique(gas_samp$service_or_fuel)), # Use unique service_or_fuel values
labels = unique(gas_samp$service_or_fuel),
title = "Gas Stations",
opacity = 0.4)
# Display the map
gas_map3
Philly Crime Data
Reading in Data
We first read in two data sets called “philly” representing several
different values having to due with crimes that have occurred in the
Philadelphia area since 2015. “Philly” has 15520 observations and 18
total variables.
philly <- read.csv("https://ecoleman451.github.io/website/Data%20Visualization/Datasets/PhillyCrimeSince2015.csv")
Mapping
Now, we can create a leaflet map looking at fatal versus non-fatal
crimes that occured in Philadelphia in the year 2023 by using the
“color” function once again. The color is dependent on whether or not a
crime was labeled as “Fatal” or “Nonfatal”. So, each category will have
a specific color, representing the type of crime (fatal vs. nonfatal)
that occurred at the time. The map is similar to the previous maps above
in which each circle point represents a specific crime. Hovering over a
point will give the “Neighborhood”, “Date”, “Race”, and “Sex”, “Age”,
and “Street” for that specific crime.
library(leaflet)
library(dplyr)
# Create color palette for fatal and non-fatal crimes
fatal <- "red"
non_fatal <- "blue"
# Create leaflet map
map <- leaflet(philly) %>%
addTiles() %>%
addCircleMarkers(
~lng, ~lat,
color = ifelse(philly$fatal == "Fatal", fatal, non_fatal),
radius = 5,
label = ~paste("Neighborhood: ", neighborhood,
"Date: ", date,
"Race: ", race,
"Sex: ", sex,
"Age: ", age,
"Street: ", street_name),
labelOptions = labelOptions(
direction = "auto"
)
) %>%
addLegend(
position = "bottomright",
colors = c(fatal, non_fatal),
labels = c("Fatal", "Non-Fatal"),
title = "Crime Type"
) %>%
addScaleBar() %>%
addControl(
html = "<h4>Philadelphia Crime Locations (2015-2024)</h4>",
position = "topright"
)
# Display the map
map
Eyeballing the map, we can see that there seems to be a significant
amount more of non-fatal crimes versus fatal crimes. Further analysis
would be needed to confirm this, of course.
Philly Crime Data
Reading in Data
We first read in a data set representing several different values
having to due with the city of Philadelphia. The data, called “Philly”,
contains information on Shootings that have occurred in the area and
categorizes them as either “Fatal” or “Non-Fatal”. “Philly” has 15555
observations and 21 total variables.
philly <- na.omit(st_read("https://pengdsci.github.io/STA553VIZ/w08/PhillyShootings.geojson"))
phillyNeighbor <- st_read("https://pengdsci.github.io/STA553VIZ/w08/Neighborhoods_Philadelphia.geojson")
Mapping
Now, we can create a leaflet map looking at fatal versus non-fatal
crimes that occured in Philadelphia by using the “color” function once
again. The color is dependent on whether or not a crime was labeled as
“Fatal” or “Nonfatal”. So, each category will have a specific color,
representing the type of crime (fatal vs. nonfatal) that occurred at the
time. Each crime location is represented with a circle marker. Hovering
over a point will display information for “Object ID”, “Year”, “Race”,
“Sex”, “Age”, “Wound”, and “Location” for each of the crime points.
# Load required libraries
library(leaflet)
library(sf)
# Convert 'philly' data to sf object
philly_sf <- st_as_sf(philly, coords = c("point_x", "point_y"), crs = 4326)
# Define color palette for fatal and non-fatal crimes
fatal_color <- "red"
non_fatal_color <- "gold"
# Create leaflet map
map <- leaflet() %>%
addProviderTiles(providers$Esri.WorldGrayCanvas) %>%
addPolygons(data = phillyNeighbor,
color = 'skyblue',
weight = 1) %>%
addCircleMarkers(data = philly_sf,
~point_x, ~point_y,
color = ifelse(philly$fatal == 1, fatal_color, non_fatal_color),
radius = 5,
popup = ~paste("Object ID: ", objectid,
"<br>Year: ", year,
"<br>Race: ", race,
"<br>Sex: ", sex,
"<br>Age: ", age,
"<br>Wound: ", wound,
"<br>Location: ", location),
labelOptions = labelOptions(
direction = "auto"
)
) %>%
addLegend(
position = "bottomright",
colors = c("red", "gold"),
labels = c("Fatal", "Non-Fatal"),
title = "Crime Type"
) %>%
addScaleBar() %>%
addControl(
html = "<h4>Philadelphia Crime Locations (2015-2024)</h4>",
position = "topright"
) %>%
addProviderTiles(providers$Esri.WorldGrayCanvas) %>%
setView(lng = -75.1527, lat = 39.9707, zoom = 11)
# Display the map
map
Working Data and Data
Loading
Our initial dataset contains Presidential election results from the
years 2000, 2004, 2008, 2012, 2016, and 2020. The data, called
“election”, has 72617 observations and 12 variables containing
information for every state, county, election, candidate winner in each
county, and total candidate votes.
Some data cleaning was necessary in order to fix the issue of the
county FIPS code, which represents the specific 5 digit code assigned to
every county in the United States. The data set initially had some codes
containing 4 digits instead of 4 if there contained a “0” as the first
digit. For example, Autauga, Alabama’s FIPS code “01001” is recorded as
“1001” in the set. This was able to be done through the excel function
“TEXT” and was done prior to reading the data in as the set called
“election”.
Using this dataset called “election”, we want to split the data so
that we have information focusing only from the county level and a
dataset for the state level. Both sets include a new variable called
“party_percentage” which calculates the percentage of people that picked
the winning party in the sets’ respective state/county - “county_data”
containing election results by county and “state_data” containing
election results by state. Both sets also keep only the winning party in
the dataset.
# Load the required library
library(dplyr)
# Read the data
election <- read.csv("https://ecoleman451.github.io/website/Data%20Visualization/Datasets/PresidentialElection2000To2020.csv")
# County-level Data
county_data <- election %>%
group_by(year, state, county_name) %>%
mutate(party_percentage = candidatevotes / sum(candidatevotes) * 100) %>%
filter(party_percentage == max(party_percentage)) %>%
select(year, state, county_fips, party, candidate, candidatevotes, party_percentage)
# State-level Data
state_data <- election %>%
group_by(year, state) %>%
mutate(party_percentage = candidatevotes / sum(candidatevotes) * 100) %>%
filter(party_percentage == max(party_percentage)) %>%
select(year, state, party, candidate, candidatevotes, party_percentage)
# Save county-level data to a new CSV file
write.csv(county_data, file = "county_level_data.csv", row.names = FALSE)
# Save state-level data to a new CSV file
write.csv(state_data, file = "state_level_data.csv", row.names = FALSE)
Choropleth Map
Now that we’ve created the data set called “county_data” - focusing
solely on election results (specifically the winning party) by county
level, we can create an interactive Choropleth Map using the data
visualization tool Tableau to display presidential election results at
the county level. There are two different colors assigned to represent
the major political parties (Democrat & Republican) and the map
shades in every county to reflect which political party was the winner
in a specific election year. A filter is set to change the year(s) in
the interactive map. Hover text is also included which appears when
hovering over a specific county on the map, containing information for
“year”, “state”, “party”, “candidatevotes”, & “party_percentage” for
the respective county being hovered over.
LS0tDQp0aXRsZTogIk1hcHBpbmciDQphdXRob3I6ICJFZHdhcmQgQ29sZW1hbiINCmRhdGU6ICJXZXN0IENoZXN0ZXIgVW5pdmVyc2l0eSINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICB0b2NfZmxvYXQ6IHllcw0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIHNtb290aF9zY3JvbGw6IHllcw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgdGhlbWU6IHJlYWRhYmxlDQogICAgZWRpdG9yX29wdGlvbnM6DQogICAgICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lDQotLS0NCg0KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4NCi8qIENvbW1vbiBzdHlsZXMgKi8NCmRpdiNUT0MgbGkgew0KICAgIGxpc3Qtc3R5bGU6bm9uZTsNCiAgICBiYWNrZ3JvdW5kLWNvbG9yOmxpZ2h0Z3JheTsNCiAgICBiYWNrZ3JvdW5kLWltYWdlOm5vbmU7DQogICAgYmFja2dyb3VuZC1yZXBlYXQ6bm9uZTsNCiAgICBiYWNrZ3JvdW5kLXBvc2l0aW9uOjA7DQogICAgZm9udC1mYW1pbHk6IEFyaWFsLCBIZWx2ZXRpY2EsIHNhbnMtc2VyaWY7DQogICAgY29sb3I6ICM3ODBjMGM7DQp9DQoNCmgxLnRpdGxlIHsNCiAgICBmb250LXNpemU6IDI0cHg7DQogICAgY29sb3I6IERhcmtSZWQ7DQogICAgdGV4dC1hbGlnbjogY2VudGVyOw0KICAgIGZvbnQtZmFtaWx5OiBBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmOw0KICAgIGZvbnQtdmFyaWFudC1jYXBzOiBub3JtYWw7DQp9DQpoNC5hdXRob3IgeyANCiAgICBmb250LXNpemU6IDE4cHg7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IERhcmtSZWQ7DQogICAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KaDQuZGF0ZSB7IA0KICAgIGZvbnQtc2l6ZTogMThweDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogRGFya0JsdWU7DQogICAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KaDEgeyANCiAgICBmb250LXNpemU6IDIycHg7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IGRhcmtyZWQ7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KaDIgeyANCiAgICBmb250LXNpemU6IDE4cHg7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IG5hdnk7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCmgzIHsgDQogICAgZm9udC1zaXplOiAxOHB4Ow0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQpoNCB7IA0KICAgIGZvbnQtc2l6ZTogMThweDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogZGFya3JlZDsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQovKiBUYWIgZmVhdHVyZXMgKi8NCi5uYXY+bGk+YSB7DQogICAgcG9zaXRpb246IHJlbGF0aXZlOw0KICAgIGRpc3BsYXk6IGJsb2NrOw0KICAgIHBhZGRpbmc6IDJweCAxNXB4Ow0KICAgIGNvbG9yOiAjOTkwMDAwOw0KfQ0KLm5hdi1waWxscz5saS5hY3RpdmU+YSwgLm5hdi1waWxscz5saS5hY3RpdmU+YTpob3ZlciwgLm5hdi1waWxscz5saS5hY3RpdmU+YTpmb2N1cyB7DQogICAgY29sb3I6ICNmZmZmZmY7DQogICAgYmFja2dyb3VuZC1jb2xvcjogIzk5MDAwMDsNCn0NCi8qDQpuYXYtcGlsbHM+bGk6bnRoLWNoaWxkKDIpIHsNCiAgICBiYWNrZ3JvdW5kOiBncmVlbjsNCiB9DQogKi8NCmltZyB7DQogICAgYm9yZGVyOiAxcHggc29saWQgIzU1NTsNCn0NCjwvc3R5bGU+DQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFLCBjb21tZW50PU5BfQ0Kb3B0aW9ucyhyZXBvcyA9IGxpc3QoQ1JBTj0iaHR0cDovL2NyYW4ucnN0dWRpby5jb20vIikpDQppZiAoIXJlcXVpcmUoInRpZHl2ZXJzZSIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQ0KICAgbGlicmFyeSh0aWR5dmVyc2UpDQp9DQppZiAoIXJlcXVpcmUoImtuaXRyIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoImtuaXRyIikNCiAgIGxpYnJhcnkoa25pdHIpDQp9DQppZiAoIXJlcXVpcmUoImNvd3Bsb3QiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygiY293cGxvdCIpDQogICBsaWJyYXJ5KGNvd3Bsb3QpDQp9DQppZiAoIXJlcXVpcmUoImxhdGV4MmV4cCIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJsYXRleDJleHAiKQ0KICAgbGlicmFyeShsYXRleDJleHApDQp9DQppZiAoIXJlcXVpcmUoInBsb3RseSIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJwbG90bHkiKQ0KICAgbGlicmFyeShwbG90bHkpDQp9DQppZiAoIXJlcXVpcmUoImdhcG1pbmRlciIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJnYXBtaW5kZXIiKQ0KICAgbGlicmFyeShnYXBtaW5kZXIpDQp9DQppZiAoIXJlcXVpcmUoInBuZyIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygicG5nIikgICAgDQogICAgbGlicmFyeSgicG5nIikNCn0NCmlmICghcmVxdWlyZSgiUkN1cmwiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoIlJDdXJsIikgICAgDQogICAgbGlicmFyeSgiUkN1cmwiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJjb2xvdXJwaWNrZXIiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImNvbG91cnBpY2tlciIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJjb2xvdXJwaWNrZXIiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJnZ2FuaW1hdGUiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImdnYW5pbWF0ZSIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJnZ2FuaW1hdGUiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJnaWZza2kiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImdpZnNraSIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJnaWZza2kiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJtYWdpY2siKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoIm1hZ2ljayIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJtYWdpY2siKQ0KfQ0KaWYgKCFyZXF1aXJlKCJnckRldmljZXMiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImdyRGV2aWNlcyIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJnckRldmljZXMiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJqcGVnIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJqcGVnIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoImpwZWciKQ0KfQ0KaWYgKCFyZXF1aXJlKCJnZ3JpZGdlcyIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygiZ2dyaWRnZXMiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgiZ2dyaWRnZXMiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJwbHlyIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJwbHlyIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoInBseXIiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJnZ2lyYXBoIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJnZ2lyYXBoIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoImdnaXJhcGgiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJoaWdoY2hhcnRlciIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygiaGlnaGNoYXJ0ZXIiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgiaGlnaGNoYXJ0ZXIiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJmb3JlY2FzdCIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygiZm9yZWNhc3QiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgiZm9yZWNhc3QiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJsZWFmbGV0IikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJsZWFmbGV0IikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoImxlYWZsZXQiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJzZiIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygic2YiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgic2YiKQ0KfQ0KIyMgDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgIHdhcm5pbmcgPSBGQUxTRSwgICANCiAgICAgICAgICAgICAgICAgICAgICByZXN1bHQgPSBUUlVFLCAgIA0KICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICBjb21tZW50ID0gTkEpDQojIGNvZGUgY2h1bmsgc3BlY2lmaWVzIHdoZXRoZXIgdGhlIFIgY29kZSwgd2FybmluZ3MsIGFuZCBvdXRwdXQgDQojIHdpbGwgYmUgaW5jbHVkZWQgaW4gdGhlIG91dHB1dCBmaWxlcy4NCmlmICghcmVxdWlyZSgiU3RhdDJEYXRhIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoIlN0YXQyRGF0YSIpDQogICBsaWJyYXJ5KFN0YXQyRGF0YSkNCn0NCmlmICghcmVxdWlyZSgia25pdHIiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKQ0KICAgbGlicmFyeShrbml0cikNCn0NCg0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICB3YXJuaW5nID0gRkFMU0UsICAgDQogICAgICAgICAgICAgICAgICAgICAgcmVzdWx0ID0gVFJVRSwgICANCiAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgICAgY29tbWVudCA9IE5BKQ0KYGBgDQoNCiMgR2FzIERhdGENCiMjIFJlYWRpbmcgaW4gRGF0YQ0KICBXZSBmaXJzdCByZWFkIGluIHR3byBkYXRhIHNldHMgY2FsbGVkICJnYXMiIHJlcHJlc2VudGluZyBzZXZlcmFsIGRpZmZlcmVudCB2YWx1ZXMgaGF2aW5nIHRvIGR1ZSB3aXRoIGdhcyBzdGF0aW9ucyBpbiB0aGUgVW5pdGVkIFN0YXRlcy4gIkdhcyIgaGFzIDcyNzk4IG9ic2VydmF0aW9ucyBhbmQgMzIgdG90YWwgdmFyaWFibGVzLg0KYGBge3IsIGNvbW1lbnQ9TkF9DQpnYXMgPC0gcmVhZC5jc3YoImh0dHBzOi8vZWNvbGVtYW40NTEuZ2l0aHViLmlvL3dlYnNpdGUvRGF0YSUyMFZpc3VhbGl6YXRpb24vRGF0YXNldHMvUE9DLmNzdiIpDQpgYGANCg0KIyBNYXBwaW5nDQojIyBTaW1wbGUgTGVhZmxldCBNYXANCiAgSW4gdGhlIGZvbGxvd2luZyBtYXAsIGVhY2ggcG9pbnQgcmVwcmVzZW50cyB0aGUgbGF0aXR1ZGUgYW5kIGxvbmdpdHVkZSB2YWx1ZXMgZm9yIGEgc3BlY2lmaWMgZ2FzIHN0YXRpb24gKHJlcHJlc2VudGVkIGJ5ICJ4Y29vcmQiIGFuZCAieWNvb3JkIiByZXNwZWN0aXZlbHkgaW4gdGhlICJnYXMiIGRhdGEgc2V0KS4gSG92ZXJpbmcgb3ZlciBlYWNoIHBvaW50LCB5b3Ugd2lsbCBzZWUgdGhlICJTdGF0ZSIsICJDb3VudHkiLCAiQWRkcmVzcyIsIGFuZCAiWmlwIENvZGUiIGZvciB0aGF0IHNwZWNpZmljIGdhcyBzdGF0aW9uLiBUaGUgcmVzdWx0cyBhcmUgYmVsb3c6DQpgYGB7ciwgY29tbWVudD1OQX0NCiBnYXNfc2FtcCA8LSBnYXMgJT4lIHNhbXBsZV9uKDUwMCkNCg0KIyBDcmVhdGUgYSBsZWFmbGV0IG1hcA0KZ2FzX21hcCA8LSBsZWFmbGV0KGRhdGEgPSBnYXNfc2FtcCkgJT4lDQogIGFkZFRpbGVzKCkgJT4lDQogIGFkZE1hcmtlcnMoDQogICAgbG5nID0gfnhjb29yZCwNCiAgICBsYXQgPSB+eWNvb3JkLA0KICAgIHBvcHVwID0gfnBhc3RlKCJTdGF0ZTogIiwgU1RBVEUsICI8YnI+IiwNCiAgICAgICAgICAgICAgICAgICAiQ291bnR5OiAiLCBjb3VudHksICI8YnI+IiwNCiAgICAgICAgICAgICAgICAgICAiQWRkcmVzczogIiwgQUREUkVTUywgIjxicj4iLA0KICAgICAgICAgICAgICAgICAgICJaaXAgQ29kZTogIiwgWklQbmV3KQ0KICApDQojIERpc3BsYXkgdGhlIG1hcA0KZ2FzX21hcA0KYGBgDQoNCiMjIExlYWZsZXQgTWFwDQogIEJlbG93LCB3ZSBjcmVhdGUgYSBzbGlnaHRseSBtb3JlIGJldHRlciBsZWFmbGV0IG1hcCBieSB1c2luZyB0aGUgInJhZGl1cyIgYW5kICJjb2xvciIgZnVuY3Rpb25zLiBIZXJlLCB3ZSBoYXZlIHRoZSByYWRpdXMgZml4ZWQgYXQgNSwgdGhlIGNvbG9yIGZpeGVkIGF0IGJsdWUsIGFuZCB0aGUgbWFya2VycyBhcyBjaXJjbGUgcG9pbnRzIGluc3RlYWQgb2YgbG9jYXRpb24gbWFya2Vycy4gVGhlIG1hcCBpcyBzaW1pbGFyIHRvIHRoZSBvbmUgYWJvdmUgaW4gd2hpY2ggZWFjaCBjaXJjbGUgcG9pbnQgcmVwcmVzZW50cyBhIGdhcyBzdGF0aW9uLiBIb3ZlcmluZyBvdmVyIGEgcG9pbnQgd2lsbCBvbmNlIGFnYWluIGdpdmUgdGhlICJTdGF0ZSIsICJDb3VudHkiLCAiQWRkcmVzcyIsIGFuZCAiWmlwIENvZGUiIGZvciB0aGF0IHNwZWNpZmljIGdhcyBzdGF0aW9uLg0KYGBge3IsIGNvbW1lbnQ9TkF9DQojIENyZWF0ZSBhIGxlYWZsZXQgbWFwDQpnYXNfbWFwMiA8LSBsZWFmbGV0KGRhdGEgPSBnYXNfc2FtcCkgJT4lDQogIGFkZFRpbGVzKCkgJT4lDQogIHNldFZpZXcobG5nID0gbWVhbihnYXNfc2FtcCR4Y29vcmQpLCANCiAgICAgICAgICBsYXQgPSBtZWFuKGdhc19zYW1wJHljb29yZCksIA0KICAgICAgICAgIHpvb20gPSAxMykgJT4lDQogIGFkZFByb3ZpZGVyVGlsZXMoIkVzcmkuV29ybGRHcmF5Q2FudmFzIikgJT4lDQogIGFkZENpcmNsZU1hcmtlcnMoDQogICAgfnhjb29yZCwgDQogICAgfnljb29yZCwNCiAgICBjb2xvciA9ICJibHVlIiwgICMgQWRqdXN0IGNvbG9yIGFzIG5lZWRlZA0KICAgIHJhZGl1cyA9IDUsICAjIEFkanVzdCByYWRpdXMgYXMgbmVlZGVkDQogICAgc3Ryb2tlID0gRkFMU0UsIA0KICAgIGZpbGxPcGFjaXR5ID0gMC40LA0KICAgIGxhYmVsID0gfnBhc3RlKCJTdGF0ZTogIiwgU1RBVEUsDQogICAgICAgICAgICAgICAgICAgIkNvdW50eTogIiwgY291bnR5LA0KICAgICAgICAgICAgICAgICAgICJBZGRyZXNzOiAiLCBBRERSRVNTLA0KICAgICAgICAgICAgICAgICAgICJaaXAgQ29kZTogIiwgWklQbmV3KQ0KICApICU+JQ0KICBhZGRMZWdlbmQocG9zaXRpb24gPSAiYm90dG9tcmlnaHQiLCANCiAgICAgICAgICAgIGNvbG9ycyA9ICJibHVlIiwgICMgQWRqdXN0IGNvbG9yIGFzIG5lZWRlZA0KICAgICAgICAgICAgbGFiZWxzID0gIkdhcyBTdGF0aW9uIiwNCiAgICAgICAgICAgIHRpdGxlID0gIkdhcyBTdGF0aW9ucyIsDQogICAgICAgICAgICBvcGFjaXR5ID0gMC40KQ0KDQojIERpc3BsYXkgdGhlIG1hcA0KZ2FzX21hcDINCmBgYA0KDQojIyBCZXN0IE1hcA0KIFRoaXMgdGltZSwgd2UgY3JlYXRlIGEgc2xpZ2h0bHkgbW9yZSBjb21wbGV4IGxlYWZsZXQgbWFwIGJ5IHVzaW5nIHRoZSAicmFkaXVzIiBhbmQgImNvbG9yIiBmdW5jdGlvbnMgb25jZSBhZ2Fpbi4gSGVyZSwgd2UgaGF2ZSB0aGUgcmFkaXVzIGRlcGVuZGVudCBvbiB0aGUgbnVtYmVyIG9mIFBPQ3MgKHBvaW50cyBvZiBjb21wcm9taXNlKSBpbiBhIGdhcyBzdGF0aW9uJ3MgcmVzcGVjdGl2ZSBaSVAgQ29kZS4gVGhpcyBtZWFucyB0aGF0IHRoZSBsYXJnZXIgYSBwb2ludCBhcHBlYXJzIG9uIHRoZSBtYXAsIHRoZSBtb3JlIFBPQ3MgZXhpc3QgaW4gdGhhdCBzdGF0aW9uJ3MgWklQIENvZGUuIFRoZSBjb2xvciBpcyBkZXBlbmRlbnQgb24gd2hldGhlciBvciBub3QgYSBnYXMgc3RhdGlvbiBwcm92aWRlcyAiRnVlbCIsICJTZXJ2aWNlIE9ubHkiIG9yICJCb3RoIiBmdWVsIGFuZCBzZXJ2aWNlcy4gU28sIGVhY2ggb2YgdGhvc2UgdGhyZWUgY2F0ZWdvcmllcyB3aWxsIGhhdmUgYSBzcGVjaWZpYyBjb2xvciwgcmVwcmVzZW50aW5nIHRoZSBzZXJ2aWNlcyBwcm92aWRlZCBhdCBhIHNwZWNpZmljIGdhcyBzdGF0aW9uLiBJbiB0aGUgZGF0YSwgd2UgZG8gbm90IGdldCBhbnkgZ2FzIHN0YXRpb25zIHRoYXQgcHJvdmlkZSAiU2VydmljZSBPbmx5Iiwgc28gb25seSB0aGUgY2F0ZWdvcmllcyAiRnVlbCIgYW5kICJCb3RoIiB3aWxsIGFwcGVhciBvbiB0aGUgbWFwLiBUaGUgbWFwIGlzIHNpbWlsYXIgdG8gdGhlIHByZXZpb3VzIG1hcHMgYWJvdmUgaW4gd2hpY2ggZWFjaCBjaXJjbGUgcG9pbnQgcmVwcmVzZW50cyBhIGdhcyBzdGF0aW9uLiBIb3ZlcmluZyBvdmVyIGEgcG9pbnQgd2lsbCBvbmNlIGFnYWluIGdpdmUgdGhlICJTdGF0ZSIsICJDb3VudHkiLCAiQWRkcmVzcyIsIGFuZCAiWmlwIENvZGUiIGZvciB0aGF0IHNwZWNpZmljIGdhcyBzdGF0aW9uLg0KYGBge3IsIGNvbW1lbnQ9TkF9DQojIENyZWF0ZSBhIGNvbG9yIHBhbGV0dGUgYmFzZWQgb24gc2VydmljZV9vcl9mdWVsIHZhbHVlcw0Kc2VydmljZV9wYWxldHRlIDwtIGNvbG9yRmFjdG9yKHBhbGV0dGUgPSAiU2V0MSIsIGRvbWFpbiA9IGdhc19zYW1wJHNlcnZpY2Vfb3JfZnVlbCkNCg0KIyBDcmVhdGUgdGhlIGxlYWZsZXQgbWFwDQpnYXNfbWFwMyA8LSBsZWFmbGV0KGRhdGEgPSBnYXNfc2FtcCkgJT4lDQogIGFkZFRpbGVzKCkgJT4lDQogIGFkZFByb3ZpZGVyVGlsZXMoIkVzcmkuV29ybGRHcmF5Q2FudmFzIikgJT4lDQogIGFkZENpcmNsZU1hcmtlcnMoDQogICAgfnhjb29yZCwgDQogICAgfnljb29yZCwNCiAgICBjb2xvciA9IH5zZXJ2aWNlX3BhbGV0dGUoc2VydmljZV9vcl9mdWVsKSwgICMgVXNlIGNvbG9yRmFjdG9yDQogICAgcmFkaXVzID0gZ2FzX3NhbXAkWklQUE9DICogMTAsICAjIEFkanVzdCByYWRpdXMgYXMgbmVlZGVkDQogICAgc3Ryb2tlID0gRkFMU0UsIA0KICAgIGZpbGxPcGFjaXR5ID0gMC40LA0KICAgIGxhYmVsID0gfnBhc3RlKCJTdGF0ZTogIiwgU1RBVEUsICI8YnI+IiwNCiAgICAgICAgICAgICAgICAgICAiQ291bnR5OiAiLCBjb3VudHksICI8YnI+IiwNCiAgICAgICAgICAgICAgICAgICAiQWRkcmVzczogIiwgQUREUkVTUywgIjxicj4iLA0KICAgICAgICAgICAgICAgICAgICJaaXAgQ29kZTogIiwgWklQbmV3KQ0KICApICU+JQ0KICBhZGRMZWdlbmQocG9zaXRpb24gPSAiYm90dG9tcmlnaHQiLCANCiAgICAgICAgICAgIGNvbG9ycyA9IHNlcnZpY2VfcGFsZXR0ZSh1bmlxdWUoZ2FzX3NhbXAkc2VydmljZV9vcl9mdWVsKSksICAjIFVzZSB1bmlxdWUgc2VydmljZV9vcl9mdWVsIHZhbHVlcw0KICAgICAgICAgICAgbGFiZWxzID0gdW5pcXVlKGdhc19zYW1wJHNlcnZpY2Vfb3JfZnVlbCksDQogICAgICAgICAgICB0aXRsZSA9ICJHYXMgU3RhdGlvbnMiLA0KICAgICAgICAgICAgb3BhY2l0eSA9IDAuNCkNCg0KIyBEaXNwbGF5IHRoZSBtYXANCmdhc19tYXAzDQpgYGANCg0KDQojIFBoaWxseSBDcmltZSBEYXRhDQojIyBSZWFkaW5nIGluIERhdGENCiAgV2UgZmlyc3QgcmVhZCBpbiB0d28gZGF0YSBzZXRzIGNhbGxlZCAicGhpbGx5IiByZXByZXNlbnRpbmcgc2V2ZXJhbCBkaWZmZXJlbnQgdmFsdWVzIGhhdmluZyB0byBkdWUgd2l0aCBjcmltZXMgdGhhdCBoYXZlIG9jY3VycmVkIGluIHRoZSBQaGlsYWRlbHBoaWEgYXJlYSBzaW5jZSAyMDE1LiAiUGhpbGx5IiBoYXMgMTU1MjAgb2JzZXJ2YXRpb25zIGFuZCAxOCB0b3RhbCB2YXJpYWJsZXMuDQpgYGB7ciwgY29tbWVudD1OQX0NCnBoaWxseSA8LSByZWFkLmNzdigiaHR0cHM6Ly9lY29sZW1hbjQ1MS5naXRodWIuaW8vd2Vic2l0ZS9EYXRhJTIwVmlzdWFsaXphdGlvbi9EYXRhc2V0cy9QaGlsbHlDcmltZVNpbmNlMjAxNS5jc3YiKQ0KYGBgDQojIyBDb252ZXJ0IERhdGUgVmFyaWFibGUgdG8gRGF0ZSBGb3JtYXQgYW5kIFN1YnNldA0KICBXZSB3YW50IHRvIG9ubHkgaGF2ZSAyMDIzIGRhdGEgaW4gb3VyIGZpbmFsIHN1YnNldCBmb3Igb3VyIG1hcC4gU2luY2UgdGhlcmUgZG9lc24ndCBleGlzdCBhIHZhcmlhYmxlIGZvciB5ZWFyLCB3ZSBoYXZlIHRvIGNyZWF0ZSBvbmUgdXNpbmcgdGhlIHZhcmlhYmxlIGRhdGUgdGhhdCBhbHJlYWR5IGV4aXN0cyBpbiB0aGUgZGF0YXNldC4gT25jZSB3ZSBoYXZlIG91ciBZZWFyIHZhcmlhYmxlLCB3ZSBjYW4gZWFzaWx5IHN1YnNldCB0aGUgZGF0YSB0byBmb2N1cyBvbmx5IG9uIDIwMjMgZGF0YS4gTm93LCBvdXIgbmV3IGRhdGEgc2V0IGhhcyAxNjY2IG9ic2VydmF0aW9ucyBhbmQgMTkgdmFyaWFibGVzLCBub3cgaW5jbHVkaW5nIFllYXIuDQpgYGB7ciwgY29tbWVudCA9IE5BfQ0KIyBDb252ZXJ0IGRhdGUgdmFyaWFibGUgdG8gZGF0ZSBmb3JtYXQNCnBoaWxseSRkYXRlIDwtIGFzLkRhdGUocGhpbGx5JGRhdGUsIGZvcm1hdCA9ICIlbS8lZC8lWSAlSDolTSIpDQoNCiMgRXh0cmFjdCB5ZWFyIGZyb20gZGF0ZSB2YXJpYWJsZQ0KcGhpbGx5JHllYXIgPC0gZm9ybWF0KHBoaWxseSRkYXRlLCAiJVkiKQ0KDQpwaGlsbHkgPC0gc3Vic2V0KHBoaWxseSwgeWVhcj09IjIwMjMiKQ0KYGBgDQoNCiMjIE1hcHBpbmcNCiAgTm93LCB3ZSBjYW4gY3JlYXRlIGEgbGVhZmxldCBtYXAgbG9va2luZyBhdCBmYXRhbCB2ZXJzdXMgbm9uLWZhdGFsIGNyaW1lcyB0aGF0IG9jY3VyZWQgaW4gUGhpbGFkZWxwaGlhIGluIHRoZSB5ZWFyIDIwMjMgYnkgdXNpbmcgdGhlICJjb2xvciIgZnVuY3Rpb24gb25jZSBhZ2Fpbi4gVGhlIGNvbG9yIGlzIGRlcGVuZGVudCBvbiB3aGV0aGVyIG9yIG5vdCBhIGNyaW1lIHdhcyBsYWJlbGVkIGFzICJGYXRhbCIgb3IgIk5vbmZhdGFsIi4gU28sIGVhY2ggY2F0ZWdvcnkgd2lsbCBoYXZlIGEgc3BlY2lmaWMgY29sb3IsIHJlcHJlc2VudGluZyB0aGUgdHlwZSBvZiBjcmltZSAoZmF0YWwgdnMuIG5vbmZhdGFsKSB0aGF0IG9jY3VycmVkIGF0IHRoZSB0aW1lLiBUaGUgbWFwIGlzIHNpbWlsYXIgdG8gdGhlIHByZXZpb3VzIG1hcHMgYWJvdmUgaW4gd2hpY2ggZWFjaCBjaXJjbGUgcG9pbnQgcmVwcmVzZW50cyBhIHNwZWNpZmljIGNyaW1lLiBIb3ZlcmluZyBvdmVyIGEgcG9pbnQgd2lsbCBnaXZlIHRoZSAiTmVpZ2hib3Job29kIiwgIkRhdGUiLCAiUmFjZSIsIGFuZCAiU2V4IiwgIkFnZSIsIGFuZCAiU3RyZWV0IiBmb3IgdGhhdCBzcGVjaWZpYyBjcmltZS4NCmBgYHtyLCBjb21tZW50PU5BfQ0KbGlicmFyeShsZWFmbGV0KQ0KbGlicmFyeShkcGx5cikNCiMgQ3JlYXRlIGNvbG9yIHBhbGV0dGUgZm9yIGZhdGFsIGFuZCBub24tZmF0YWwgY3JpbWVzDQpmYXRhbCA8LSAicmVkIg0Kbm9uX2ZhdGFsIDwtICJibHVlIg0KDQojIENyZWF0ZSBsZWFmbGV0IG1hcA0KbWFwIDwtIGxlYWZsZXQocGhpbGx5KSAlPiUNCiAgYWRkVGlsZXMoKSAlPiUNCiAgYWRkQ2lyY2xlTWFya2VycygNCiAgICB+bG5nLCB+bGF0LA0KICAgIGNvbG9yID0gaWZlbHNlKHBoaWxseSRmYXRhbCA9PSAiRmF0YWwiLCBmYXRhbCwgbm9uX2ZhdGFsKSwNCiAgICByYWRpdXMgPSA1LA0KICAgIGxhYmVsID0gfnBhc3RlKCJOZWlnaGJvcmhvb2Q6ICIsIG5laWdoYm9yaG9vZCwNCiAgICAgICAgICAgICAgICAgICAiRGF0ZTogIiwgZGF0ZSwNCiAgICAgICAgICAgICAgICAgICAiUmFjZTogIiwgcmFjZSwNCiAgICAgICAgICAgICAgICAgICAiU2V4OiAiLCBzZXgsDQogICAgICAgICAgICAgICAgICAgIkFnZTogIiwgYWdlLA0KICAgICAgICAgICAgICAgICAgICJTdHJlZXQ6ICIsIHN0cmVldF9uYW1lKSwNCiAgICBsYWJlbE9wdGlvbnMgPSBsYWJlbE9wdGlvbnMoDQogICAgICBkaXJlY3Rpb24gPSAiYXV0byINCiAgICApDQogICkgJT4lDQogIGFkZExlZ2VuZCgNCiAgICBwb3NpdGlvbiA9ICJib3R0b21yaWdodCIsDQogICAgY29sb3JzID0gYyhmYXRhbCwgbm9uX2ZhdGFsKSwNCiAgICBsYWJlbHMgPSBjKCJGYXRhbCIsICJOb24tRmF0YWwiKSwNCiAgICB0aXRsZSA9ICJDcmltZSBUeXBlIg0KICApICU+JQ0KICBhZGRTY2FsZUJhcigpICU+JQ0KICBhZGRDb250cm9sKA0KICAgIGh0bWwgPSAiPGg0PlBoaWxhZGVscGhpYSBDcmltZSBMb2NhdGlvbnMgKDIwMTUtMjAyNCk8L2g0PiIsDQogICAgcG9zaXRpb24gPSAidG9wcmlnaHQiDQogICkNCg0KIyBEaXNwbGF5IHRoZSBtYXANCm1hcA0KYGBgDQogIEV5ZWJhbGxpbmcgdGhlIG1hcCwgd2UgY2FuIHNlZSB0aGF0IHRoZXJlIHNlZW1zIHRvIGJlIGEgc2lnbmlmaWNhbnQgYW1vdW50IG1vcmUgb2Ygbm9uLWZhdGFsIGNyaW1lcyB2ZXJzdXMgZmF0YWwgY3JpbWVzLiBGdXJ0aGVyIGFuYWx5c2lzIHdvdWxkIGJlIG5lZWRlZCB0byBjb25maXJtIHRoaXMsIG9mIGNvdXJzZS4NCg0KDQojIFBoaWxseSBDcmltZSBEYXRhDQojIyBSZWFkaW5nIGluIERhdGENCiAgV2UgZmlyc3QgcmVhZCBpbiBhIGRhdGEgc2V0IHJlcHJlc2VudGluZyBzZXZlcmFsIGRpZmZlcmVudCB2YWx1ZXMgaGF2aW5nIHRvIGR1ZSB3aXRoIHRoZSBjaXR5IG9mIFBoaWxhZGVscGhpYS4gVGhlIGRhdGEsIGNhbGxlZCAiUGhpbGx5IiwgY29udGFpbnMgaW5mb3JtYXRpb24gb24gU2hvb3RpbmdzIHRoYXQgaGF2ZSBvY2N1cnJlZCBpbiB0aGUgYXJlYSBhbmQgY2F0ZWdvcml6ZXMgdGhlbSBhcyBlaXRoZXIgIkZhdGFsIiBvciAiTm9uLUZhdGFsIi4gIlBoaWxseSIgaGFzIDE1NTU1IG9ic2VydmF0aW9ucyBhbmQgMjEgdG90YWwgdmFyaWFibGVzLg0KYGBge3IsIGNvbW1lbnQ9TkEsIHJlc3VsdHM9RkFMU0V9DQpwaGlsbHkgIDwtIG5hLm9taXQoc3RfcmVhZCgiaHR0cHM6Ly9wZW5nZHNjaS5naXRodWIuaW8vU1RBNTUzVklaL3cwOC9QaGlsbHlTaG9vdGluZ3MuZ2VvanNvbiIpKQ0KcGhpbGx5TmVpZ2hib3IgIDwtIHN0X3JlYWQoImh0dHBzOi8vcGVuZ2RzY2kuZ2l0aHViLmlvL1NUQTU1M1ZJWi93MDgvTmVpZ2hib3Job29kc19QaGlsYWRlbHBoaWEuZ2VvanNvbiIpDQpgYGANCg0KIyMgTWFwcGluZw0KICBOb3csIHdlIGNhbiBjcmVhdGUgYSBsZWFmbGV0IG1hcCBsb29raW5nIGF0IGZhdGFsIHZlcnN1cyBub24tZmF0YWwgY3JpbWVzIHRoYXQgb2NjdXJlZCBpbiBQaGlsYWRlbHBoaWEgYnkgdXNpbmcgdGhlICJjb2xvciIgZnVuY3Rpb24gb25jZSBhZ2Fpbi4gVGhlIGNvbG9yIGlzIGRlcGVuZGVudCBvbiB3aGV0aGVyIG9yIG5vdCBhIGNyaW1lIHdhcyBsYWJlbGVkIGFzICJGYXRhbCIgb3IgIk5vbmZhdGFsIi4gU28sIGVhY2ggY2F0ZWdvcnkgd2lsbCBoYXZlIGEgc3BlY2lmaWMgY29sb3IsIHJlcHJlc2VudGluZyB0aGUgdHlwZSBvZiBjcmltZSAoZmF0YWwgdnMuIG5vbmZhdGFsKSB0aGF0IG9jY3VycmVkIGF0IHRoZSB0aW1lLiBFYWNoIGNyaW1lIGxvY2F0aW9uIGlzIHJlcHJlc2VudGVkIHdpdGggYSBjaXJjbGUgbWFya2VyLiBIb3ZlcmluZyBvdmVyIGEgcG9pbnQgd2lsbCBkaXNwbGF5IGluZm9ybWF0aW9uIGZvciAiT2JqZWN0IElEIiwgIlllYXIiLCAiUmFjZSIsICJTZXgiLCAiQWdlIiwgIldvdW5kIiwgYW5kICJMb2NhdGlvbiIgZm9yIGVhY2ggb2YgdGhlIGNyaW1lIHBvaW50cy4NCmBgYHtyfQ0KIyBMb2FkIHJlcXVpcmVkIGxpYnJhcmllcw0KbGlicmFyeShsZWFmbGV0KQ0KbGlicmFyeShzZikNCg0KIyBDb252ZXJ0ICdwaGlsbHknIGRhdGEgdG8gc2Ygb2JqZWN0DQpwaGlsbHlfc2YgPC0gc3RfYXNfc2YocGhpbGx5LCBjb29yZHMgPSBjKCJwb2ludF94IiwgInBvaW50X3kiKSwgY3JzID0gNDMyNikNCg0KIyBEZWZpbmUgY29sb3IgcGFsZXR0ZSBmb3IgZmF0YWwgYW5kIG5vbi1mYXRhbCBjcmltZXMNCmZhdGFsX2NvbG9yIDwtICJyZWQiDQpub25fZmF0YWxfY29sb3IgPC0gImdvbGQiDQoNCiMgQ3JlYXRlIGxlYWZsZXQgbWFwDQptYXAgPC0gbGVhZmxldCgpICU+JQ0KICBhZGRQcm92aWRlclRpbGVzKHByb3ZpZGVycyRFc3JpLldvcmxkR3JheUNhbnZhcykgJT4lDQogIGFkZFBvbHlnb25zKGRhdGEgPSBwaGlsbHlOZWlnaGJvciwNCiAgICAgICAgICAgICAgY29sb3IgPSAnc2t5Ymx1ZScsDQogICAgICAgICAgICAgIHdlaWdodCA9IDEpICAlPiUNCiAgYWRkQ2lyY2xlTWFya2VycyhkYXRhID0gcGhpbGx5X3NmLA0KICAgICAgICAgICAgICAgICAgIH5wb2ludF94LCB+cG9pbnRfeSwNCiAgICAgICAgICAgICAgICAgICBjb2xvciA9IGlmZWxzZShwaGlsbHkkZmF0YWwgPT0gMSwgZmF0YWxfY29sb3IsIG5vbl9mYXRhbF9jb2xvciksDQogICAgICAgICAgICAgICAgICAgcmFkaXVzID0gNSwNCiAgICAgICAgICAgICAgICAgICBwb3B1cCA9IH5wYXN0ZSgiT2JqZWN0IElEOiAiLCBvYmplY3RpZCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiPGJyPlllYXI6ICIsIHllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjxicj5SYWNlOiAiLCByYWNlLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI8YnI+U2V4OiAiLCBzZXgsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjxicj5BZ2U6ICIsIGFnZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiPGJyPldvdW5kOiAiLCB3b3VuZCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiPGJyPkxvY2F0aW9uOiAiLCBsb2NhdGlvbiksDQogICAgICAgICAgICAgICAgICAgbGFiZWxPcHRpb25zID0gbGFiZWxPcHRpb25zKA0KICAgICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gImF1dG8iDQogICAgICAgICAgICAgICAgICAgKQ0KICApICU+JQ0KICBhZGRMZWdlbmQoDQogICAgcG9zaXRpb24gPSAiYm90dG9tcmlnaHQiLA0KICAgIGNvbG9ycyA9IGMoInJlZCIsICJnb2xkIiksDQogICAgbGFiZWxzID0gYygiRmF0YWwiLCAiTm9uLUZhdGFsIiksDQogICAgdGl0bGUgPSAiQ3JpbWUgVHlwZSINCiAgKSAlPiUNCiAgYWRkU2NhbGVCYXIoKSAlPiUNCiAgYWRkQ29udHJvbCgNCiAgICBodG1sID0gIjxoND5QaGlsYWRlbHBoaWEgQ3JpbWUgTG9jYXRpb25zICgyMDE1LTIwMjQpPC9oND4iLA0KICAgIHBvc2l0aW9uID0gInRvcHJpZ2h0Ig0KICApICU+JQ0KICBhZGRQcm92aWRlclRpbGVzKHByb3ZpZGVycyRFc3JpLldvcmxkR3JheUNhbnZhcykgJT4lDQogIHNldFZpZXcobG5nID0gLTc1LjE1MjcsIGxhdCA9IDM5Ljk3MDcsIHpvb20gPSAxMSkNCg0KIyBEaXNwbGF5IHRoZSBtYXANCm1hcA0KYGBgDQoNCg0KXA0KDQpcDQoNCiMgV29ya2luZyBEYXRhIGFuZCBEYXRhIExvYWRpbmcNCk91ciBpbml0aWFsIGRhdGFzZXQgY29udGFpbnMgUHJlc2lkZW50aWFsIGVsZWN0aW9uIHJlc3VsdHMgZnJvbSB0aGUgeWVhcnMgMjAwMCwgMjAwNCwgMjAwOCwgMjAxMiwgMjAxNiwgYW5kIDIwMjAuIFRoZSBkYXRhLCBjYWxsZWQgImVsZWN0aW9uIiwgaGFzIDcyNjE3IG9ic2VydmF0aW9ucyBhbmQgMTIgdmFyaWFibGVzIGNvbnRhaW5pbmcgaW5mb3JtYXRpb24gZm9yIGV2ZXJ5IHN0YXRlLCBjb3VudHksIGVsZWN0aW9uLCBjYW5kaWRhdGUgd2lubmVyIGluIGVhY2ggY291bnR5LCBhbmQgdG90YWwgY2FuZGlkYXRlIHZvdGVzLiANCg0KU29tZSBkYXRhIGNsZWFuaW5nIHdhcyBuZWNlc3NhcnkgaW4gb3JkZXIgdG8gZml4IHRoZSBpc3N1ZSBvZiB0aGUgY291bnR5IEZJUFMgY29kZSwgd2hpY2ggcmVwcmVzZW50cyB0aGUgc3BlY2lmaWMgNSBkaWdpdCBjb2RlIGFzc2lnbmVkIHRvIGV2ZXJ5IGNvdW50eSBpbiB0aGUgVW5pdGVkIFN0YXRlcy4gVGhlIGRhdGEgc2V0IGluaXRpYWxseSBoYWQgc29tZSBjb2RlcyBjb250YWluaW5nIDQgZGlnaXRzIGluc3RlYWQgb2YgNCBpZiB0aGVyZSBjb250YWluZWQgYSAiMCIgYXMgdGhlIGZpcnN0IGRpZ2l0LiBGb3IgZXhhbXBsZSwgQXV0YXVnYSwgQWxhYmFtYSdzIEZJUFMgY29kZSAiMDEwMDEiIGlzIHJlY29yZGVkIGFzICIxMDAxIiBpbiB0aGUgc2V0LiBUaGlzIHdhcyBhYmxlIHRvIGJlIGRvbmUgdGhyb3VnaCB0aGUgZXhjZWwgZnVuY3Rpb24gIlRFWFQiIGFuZCB3YXMgZG9uZSBwcmlvciB0byByZWFkaW5nIHRoZSBkYXRhIGluIGFzIHRoZSBzZXQgY2FsbGVkICJlbGVjdGlvbiIuDQoNClVzaW5nIHRoaXMgZGF0YXNldCBjYWxsZWQgImVsZWN0aW9uIiwgd2Ugd2FudCB0byBzcGxpdCB0aGUgZGF0YSBzbyB0aGF0IHdlIGhhdmUgaW5mb3JtYXRpb24gZm9jdXNpbmcgb25seSBmcm9tIHRoZSBjb3VudHkgbGV2ZWwgYW5kIGEgZGF0YXNldCBmb3IgdGhlIHN0YXRlIGxldmVsLiBCb3RoIHNldHMgaW5jbHVkZSBhIG5ldyB2YXJpYWJsZSBjYWxsZWQgInBhcnR5X3BlcmNlbnRhZ2UiIHdoaWNoIGNhbGN1bGF0ZXMgdGhlIHBlcmNlbnRhZ2Ugb2YgcGVvcGxlIHRoYXQgcGlja2VkIHRoZSB3aW5uaW5nIHBhcnR5IGluIHRoZSBzZXRzJyByZXNwZWN0aXZlIHN0YXRlL2NvdW50eSAtICJjb3VudHlfZGF0YSIgY29udGFpbmluZyBlbGVjdGlvbiByZXN1bHRzIGJ5IGNvdW50eSBhbmQgInN0YXRlX2RhdGEiIGNvbnRhaW5pbmcgZWxlY3Rpb24gcmVzdWx0cyBieSBzdGF0ZS4gQm90aCBzZXRzIGFsc28ga2VlcCBvbmx5IHRoZSB3aW5uaW5nIHBhcnR5IGluIHRoZSBkYXRhc2V0Lg0KYGBge3J9DQojIExvYWQgdGhlIHJlcXVpcmVkIGxpYnJhcnkNCmxpYnJhcnkoZHBseXIpDQoNCiMgUmVhZCB0aGUgZGF0YQ0KZWxlY3Rpb24gPC0gcmVhZC5jc3YoImh0dHBzOi8vZWNvbGVtYW40NTEuZ2l0aHViLmlvL3dlYnNpdGUvRGF0YSUyMFZpc3VhbGl6YXRpb24vRGF0YXNldHMvUHJlc2lkZW50aWFsRWxlY3Rpb24yMDAwVG8yMDIwLmNzdiIpDQoNCiMgQ291bnR5LWxldmVsIERhdGENCmNvdW50eV9kYXRhIDwtIGVsZWN0aW9uICU+JQ0KICBncm91cF9ieSh5ZWFyLCBzdGF0ZSwgY291bnR5X25hbWUpICU+JQ0KICBtdXRhdGUocGFydHlfcGVyY2VudGFnZSA9IGNhbmRpZGF0ZXZvdGVzIC8gc3VtKGNhbmRpZGF0ZXZvdGVzKSAqIDEwMCkgJT4lDQogIGZpbHRlcihwYXJ0eV9wZXJjZW50YWdlID09IG1heChwYXJ0eV9wZXJjZW50YWdlKSkgJT4lDQogIHNlbGVjdCh5ZWFyLCBzdGF0ZSwgY291bnR5X2ZpcHMsIHBhcnR5LCBjYW5kaWRhdGUsIGNhbmRpZGF0ZXZvdGVzLCBwYXJ0eV9wZXJjZW50YWdlKQ0KDQojIFN0YXRlLWxldmVsIERhdGENCnN0YXRlX2RhdGEgPC0gZWxlY3Rpb24gJT4lDQogIGdyb3VwX2J5KHllYXIsIHN0YXRlKSAlPiUNCiAgbXV0YXRlKHBhcnR5X3BlcmNlbnRhZ2UgPSBjYW5kaWRhdGV2b3RlcyAvIHN1bShjYW5kaWRhdGV2b3RlcykgKiAxMDApICU+JQ0KICBmaWx0ZXIocGFydHlfcGVyY2VudGFnZSA9PSBtYXgocGFydHlfcGVyY2VudGFnZSkpICU+JQ0KICBzZWxlY3QoeWVhciwgc3RhdGUsIHBhcnR5LCBjYW5kaWRhdGUsIGNhbmRpZGF0ZXZvdGVzLCBwYXJ0eV9wZXJjZW50YWdlKQ0KDQojIFNhdmUgY291bnR5LWxldmVsIGRhdGEgdG8gYSBuZXcgQ1NWIGZpbGUNCndyaXRlLmNzdihjb3VudHlfZGF0YSwgZmlsZSA9ICJjb3VudHlfbGV2ZWxfZGF0YS5jc3YiLCByb3cubmFtZXMgPSBGQUxTRSkNCg0KIyBTYXZlIHN0YXRlLWxldmVsIGRhdGEgdG8gYSBuZXcgQ1NWIGZpbGUNCndyaXRlLmNzdihzdGF0ZV9kYXRhLCBmaWxlID0gInN0YXRlX2xldmVsX2RhdGEuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpDQpgYGANCg0KIyBDaG9yb3BsZXRoIE1hcA0KTm93IHRoYXQgd2UndmUgY3JlYXRlZCB0aGUgZGF0YSBzZXQgY2FsbGVkICJjb3VudHlfZGF0YSIgLSBmb2N1c2luZyBzb2xlbHkgb24gZWxlY3Rpb24gcmVzdWx0cyAoc3BlY2lmaWNhbGx5IHRoZSB3aW5uaW5nIHBhcnR5KSBieSBjb3VudHkgbGV2ZWwsIHdlIGNhbiBjcmVhdGUgYW4gaW50ZXJhY3RpdmUgQ2hvcm9wbGV0aCBNYXAgdXNpbmcgdGhlIGRhdGEgdmlzdWFsaXphdGlvbiB0b29sIFRhYmxlYXUgdG8gZGlzcGxheSBwcmVzaWRlbnRpYWwgZWxlY3Rpb24gcmVzdWx0cyBhdCB0aGUgY291bnR5IGxldmVsLiBUaGVyZSBhcmUgdHdvIGRpZmZlcmVudCBjb2xvcnMgYXNzaWduZWQgdG8gcmVwcmVzZW50IHRoZSBtYWpvciBwb2xpdGljYWwgcGFydGllcyAoRGVtb2NyYXQgJiBSZXB1YmxpY2FuKSBhbmQgdGhlIG1hcCBzaGFkZXMgaW4gZXZlcnkgY291bnR5IHRvIHJlZmxlY3Qgd2hpY2ggcG9saXRpY2FsIHBhcnR5IHdhcyB0aGUgd2lubmVyIGluIGEgc3BlY2lmaWMgZWxlY3Rpb24geWVhci4gQSBmaWx0ZXIgaXMgc2V0IHRvIGNoYW5nZSB0aGUgeWVhcihzKSBpbiB0aGUgaW50ZXJhY3RpdmUgbWFwLiBIb3ZlciB0ZXh0IGlzIGFsc28gaW5jbHVkZWQgd2hpY2ggYXBwZWFycyB3aGVuIGhvdmVyaW5nIG92ZXIgYSBzcGVjaWZpYyBjb3VudHkgb24gdGhlIG1hcCwgY29udGFpbmluZyBpbmZvcm1hdGlvbiBmb3IgInllYXIiLCAic3RhdGUiLCAicGFydHkiLCAiY2FuZGlkYXRldm90ZXMiLCAmICJwYXJ0eV9wZXJjZW50YWdlIiBmb3IgdGhlIHJlc3BlY3RpdmUgY291bnR5IGJlaW5nIGhvdmVyZWQgb3Zlci4NClwNCjx0YWJsZSBib3JkZXIgPSAwIGJvcmRlcmNvbG9yPSJkYXJrZ3JlZW4iIGJnY29sb3I9JyNmNmY2ZjYnICB3aWR0aD0xMDAlICBhbGlnbiA9IGNlbnRlcj4NCjx0cj4NCjx0ZD4NCjxkaXYgY2xhc3M9J3RhYmxlYXVQbGFjZWhvbGRlcicgaWQ9J3ZpejE3MTIyNjkyOTQwMjAnIHN0eWxlPSdwb3NpdGlvbjogcmVsYXRpdmUnPjxub3NjcmlwdD48YSBocmVmPScjJz48aW1nIGFsdD0nQ2hvcm9wbGV0aCBNYXAgJyBzcmM9J2h0dHBzOiYjNDc7JiM0NztwdWJsaWMudGFibGVhdS5jb20mIzQ3O3N0YXRpYyYjNDc7aW1hZ2VzJiM0NztDaCYjNDc7Q2hvcm9wbGV0aF9NYXBfRmluYWwmIzQ3O1NoZWV0MSYjNDc7MV9yc3MucG5nJyBzdHlsZT0nYm9yZGVyOiBub25lJyAvPjwvYT48L25vc2NyaXB0PjxvYmplY3QgY2xhc3M9J3RhYmxlYXVWaXonICBzdHlsZT0nZGlzcGxheTpub25lOyc+PHBhcmFtIG5hbWU9J2hvc3RfdXJsJyB2YWx1ZT0naHR0cHMlM0ElMkYlMkZwdWJsaWMudGFibGVhdS5jb20lMkYnIC8+IDxwYXJhbSBuYW1lPSdlbWJlZF9jb2RlX3ZlcnNpb24nIHZhbHVlPSczJyAvPiA8cGFyYW0gbmFtZT0nc2l0ZV9yb290JyB2YWx1ZT0nJyAvPjxwYXJhbSBuYW1lPSduYW1lJyB2YWx1ZT0nQ2hvcm9wbGV0aF9NYXBfRmluYWwmIzQ3O1NoZWV0MScgLz48cGFyYW0gbmFtZT0ndGFicycgdmFsdWU9J25vJyAvPjxwYXJhbSBuYW1lPSd0b29sYmFyJyB2YWx1ZT0neWVzJyAvPjxwYXJhbSBuYW1lPSdzdGF0aWNfaW1hZ2UnIHZhbHVlPSdodHRwczomIzQ3OyYjNDc7cHVibGljLnRhYmxlYXUuY29tJiM0NztzdGF0aWMmIzQ3O2ltYWdlcyYjNDc7Q2gmIzQ3O0Nob3JvcGxldGhfTWFwX0ZpbmFsJiM0NztTaGVldDEmIzQ3OzEucG5nJyAvPiA8cGFyYW0gbmFtZT0nYW5pbWF0ZV90cmFuc2l0aW9uJyB2YWx1ZT0neWVzJyAvPjxwYXJhbSBuYW1lPSdkaXNwbGF5X3N0YXRpY19pbWFnZScgdmFsdWU9J3llcycgLz48cGFyYW0gbmFtZT0nZGlzcGxheV9zcGlubmVyJyB2YWx1ZT0neWVzJyAvPjxwYXJhbSBuYW1lPSdkaXNwbGF5X292ZXJsYXknIHZhbHVlPSd5ZXMnIC8+PHBhcmFtIG5hbWU9J2Rpc3BsYXlfY291bnQnIHZhbHVlPSd5ZXMnIC8+PHBhcmFtIG5hbWU9J2xhbmd1YWdlJyB2YWx1ZT0nZW4tVVMnIC8+PHBhcmFtIG5hbWU9J2ZpbHRlcicgdmFsdWU9J3B1Ymxpc2g9eWVzJyAvPjwvb2JqZWN0PjwvZGl2PiAgICAgICAgICAgICAgICANCjxzY3JpcHQgdHlwZT0ndGV4dC9qYXZhc2NyaXB0Jz4gICAgICAgICAgICAgICAgICAgIHZhciBkaXZFbGVtZW50ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3ZpejE3MTIyNjkyOTQwMjAnKTsgICAgICAgICAgICAgICAgICAgIHZhciB2aXpFbGVtZW50ID0gZGl2RWxlbWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnb2JqZWN0JylbMF07ICAgICAgICAgICAgICAgICAgICB2aXpFbGVtZW50LnN0eWxlLndpZHRoPScxMDAlJzt2aXpFbGVtZW50LnN0eWxlLmhlaWdodD0oZGl2RWxlbWVudC5vZmZzZXRXaWR0aCowLjc1KSsncHgnOyAgICAgICAgICAgICAgICAgICAgdmFyIHNjcmlwdEVsZW1lbnQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTsgICAgICAgICAgICAgICAgICAgIHNjcmlwdEVsZW1lbnQuc3JjID0gJ2h0dHBzOi8vcHVibGljLnRhYmxlYXUuY29tL2phdmFzY3JpcHRzL2FwaS92aXpfdjEuanMnOyAgICAgICAgICAgICAgICAgICAgdml6RWxlbWVudC5wYXJlbnROb2RlLmluc2VydEJlZm9yZShzY3JpcHRFbGVtZW50LCB2aXpFbGVtZW50KTsgICAgICAgICAgICAgICAgDQo8L3NjcmlwdD4NCjwvdGQ+DQo8L3RyPg0KPC90YWJsZT4gICAgICAgICAgICANClw=